home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / pi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-30  |  38.8 KB  |  1,416 lines

  1. /*
  2.  * Interface driver for the VE3IFB 8530 card (PI card)
  3.  * Copyright 1990 by Dave Perry, VE3IFB
  4.  *
  5.  * History
  6.  * Minor delinting - KA9Q 2/2/91
  7.  * March 23 92 dp - Fixed bug in B port driver where ff in the data was
  8.  *                not being handled correctly. 
  9.  *              - Fixed bug where receive packet would get clobbered if
  10.  *                a new packet was enqueued for transmission. Greatly
  11.  *                improves performance with sliding window protocols.
  12.  *                (tdelay would overwrite contents of the interrupt control
  13.  *                register in the scc).
  14.  * March 29,92 dp - Last release was based on old sources - corrected.
  15.  * 
  16.  *
  17.  * Portions of this driver were derived from the Eagle card
  18.  * driver by Art Goldman, WA3CVG. It has been very extensively
  19.  * modified from his work, due to the addition of DMA support
  20.  * and due to differences in the hardware.  The PI card is NOT
  21.  * an Eagle card clone. It is an original design by Dave Perry,
  22.  * VE3IFB.  Art's copyright notice follows:
  23.  *
  24.  *  Written by Art Goldman, WA3CVG - (c) Copyright 1987 All Rights Reserved
  25.  *  Permission for non-commercial use is hereby granted provided this notice
  26.  *  is retained.  For info call: (301) 997-3838.
  27.  *
  28.  */
  29.  
  30. #include <time.h>
  31. #include <stdio.h>
  32. #include <dos.h>
  33. #include <bios.h>
  34. #include "global.h"
  35. #include "mbuf.h"
  36. #include "iface.h"
  37. #include "pktdrvr.h"
  38. #include "netuser.h"
  39. #include "pi.h"
  40. #include "z8530.h"
  41. #include "ax25.h"
  42. #include "trace.h"
  43. #include "pc.h"
  44.  
  45. #include "session.h"
  46. #include "lapb.h"
  47. #include "proc.h"
  48. #include "ip.h"
  49. #include "devparam.h"
  50.  
  51. #ifndef FP_OFF
  52. #define FP_OFF(fp)    ((unsigned)(fp))
  53. #endif
  54. #ifndef FP_SEG
  55. #define FP_SEG(fp)    ((unsigned)((unsigned long)(fp) >> 16))
  56. #endif
  57.  
  58. static int32 pi_ctl __ARGS((struct iface *iface,int cmd,int set,int32 val));
  59. static int pi_raw __ARGS((struct iface *iface,struct mbuf *bp));
  60. static int pi_stop __ARGS((struct iface *iface));
  61. static void rts __ARGS((struct pichan *hp, int16 x));
  62. void setup_rx_dma __ARGS((struct pichan *hp));
  63. void setup_tx_dma __ARGS((struct pichan *hp, char *buffer, int length));
  64. static void tdelay __ARGS((register struct pichan *hp,unsigned int time));
  65.  
  66. static struct PITAB Pi[PIMAX];    /* Device table - one entry per card */
  67. static INTERRUPT (*pihandle[])() = {    /* handler interrupt vector table */
  68.     pi0vec,
  69.     pi1vec,
  70.     pi2vec
  71. };
  72. static int16 Page_regs[] = {
  73.     0x87,0x83,0x81,0x82,0,0x8b,0x89,0x8a
  74. };
  75. static struct pichan Pichan[2*PIMAX];    /* channel table - 2 entries per card */
  76. static int16 pinbr;
  77.  
  78. extern int16 acc_delay;    /* Delay for the 8530 chip access recovery time */
  79.  
  80. /* Setup 8253 chip for time delay */
  81. static void
  82. tdelay(hp,time)
  83. register struct pichan *hp;
  84. unsigned int time;         /* Time to delay in milliseconds */
  85. {
  86.     int n,port;
  87.     unsigned int t1;
  88.     unsigned char sc;
  89.  
  90.     if(hp->base & 2){ /* If A channel */
  91.         sc = SC1;
  92.         t1 = time;
  93.         port = hp->cardbase+TMR1;
  94.     } else {
  95.         sc = SC2;
  96.         t1 = 10 * time; /* 10s of milliseconds for the B channel */
  97.         port = hp->cardbase+TMR2;
  98.         wrtscc(hp->cardbase,hp->base+CTL,R1,EXT_INT_ENAB);
  99.     }
  100.  
  101.     /* Setup timer sc */
  102.     outportb(hp->cardbase+TMRCMD, sc|LSB_MSB|MODE0);
  103.     
  104.     /* satisfy access time restriction */
  105.     for(n=0; n<2;n++)
  106.         ;
  107.     /* times 2 to make millisecs */
  108.     outportb(port, (t1 << 1) & 0xFF);
  109.  
  110.     /* satisfy access time restriction */
  111.     for(n=0; n<2;n++)
  112.         ;
  113.     outportb(port, (t1 >> 7) & 0xFF);
  114.  
  115.     /* Enable correct int for timeout */
  116.     wrtscc(hp->cardbase,hp->base+CTL,R15,CTSIE);
  117.     wrtscc(hp->cardbase,hp->base+CTL,R0,RES_EXT_INT);
  118. }
  119.  
  120. /* Master interrupt handler.  One interrupt at a time is handled.
  121.  * here. Service routines are called from here.
  122.  */
  123. void
  124. piint(dev)
  125. int dev;
  126. {
  127.     register char st;
  128.     register int16 pcbase;
  129.     struct pichan *hp;
  130.     void b_rxint(),b_txint(),b_exint();
  131.     void a_rxint(),a_txint(),a_exint();
  132.  
  133.     Pi[dev].ints++;
  134.     pcbase = Pi[dev].addr;
  135.  
  136.     /* Read interrupt status register (only valid from channel A)
  137.      * Process all pending interrupts in while loop
  138.      */
  139.     hp = &Pichan[2 * dev];    /* Assume channel A */
  140.     while((st = rdscc(hp->cardbase,pcbase+CHANA+CTL,R3)) != 0){
  141.         if(st & CHBTxIP){
  142.             /* Channel B Transmit Int Pending */
  143.             hp = &Pichan[(2 * dev)+1];
  144.             b_txint(hp);
  145.         } else if(st & CHARxIP){
  146.             /* Channel A Rcv Interrupt Pending */
  147.             hp = &Pichan[2 * dev];
  148.             a_rxint(hp);
  149.         } else if(st & CHATxIP){
  150.             /* Channel A Transmit Int Pending */
  151.             hp = &Pichan[2 * dev];
  152.             a_txint(hp);
  153.         } else if(st & CHAEXT){
  154.             /* Channel A External Status Int */
  155.             hp = &Pichan[2 * dev];
  156.             a_exint(hp);
  157.         } else if(st & CHBRxIP){
  158.             /* Channel B Rcv Interrupt Pending */
  159.             hp = &Pichan[(2 * dev)+1];
  160.             b_rxint(hp);
  161.         } else if(st & CHBEXT){
  162.             /* Channel B External Status Int */
  163.             hp = &Pichan[(2 * dev)+1];
  164.             b_exint(hp);
  165.         }
  166.         /* Reset highest interrupt under service */
  167.         wrtscc(hp->cardbase,hp->base+CTL,R0,RES_H_IUS);
  168.     } /* End of while loop on int processing */
  169. }
  170.  
  171. static void
  172. a_exint(hp)
  173. register struct pichan *hp;
  174. {
  175.     register int16 cmd;
  176.     char st, i_state;
  177.     int length;
  178.     int32 t,ca;
  179.  
  180.     i_state = dirps();        /* disable interrupts */
  181.  
  182.     st = rdscc(hp->cardbase,hp->base+CTL,R0);     /* Fetch status */
  183.  
  184.     /* reset external status latch */
  185.     wrtscc(hp->cardbase,CTL+hp->base,R0,RES_EXT_INT);
  186.     cmd = hp->base+CTL;
  187.     hp->exints++;
  188.  
  189.     if((hp->rstate >= ACTIVE) && (st & BRK_ABRT)){    
  190.         setup_rx_dma(hp);
  191.         hp->rstate = ACTIVE;
  192.     }
  193.     switch(hp->tstate){
  194.     case ACTIVE:
  195.         free_p(hp->sndbuf);
  196.         hp->sndbuf = NULLBUF;
  197.         hp->tstate = FLAGOUT;
  198.         tdelay(hp,hp->squeldelay);
  199.         break;
  200.     case FLAGOUT:
  201.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  202.             /* Nothing to send - return to receive mode */
  203.             hp->tstate = IDLE;
  204.             rts(hp,OFF);
  205.             restore(i_state);
  206.             return;
  207.         }
  208.         /* NOTE - fall through if more to send */
  209.     case ST_TXDELAY:
  210.         /* Disable DMA chan */
  211.         outportb(DMA_MASK, DMA_DISABLE|hp->dmachan);
  212.  
  213.         /* Set up for TX dma */
  214.         wrtscc(hp->cardbase,cmd,R1,WT_FN_RDYFN|EXT_INT_ENAB);
  215.  
  216.         /* Get all chars */
  217.         length = pullup(&hp->sndbuf,hp->txdmabuf,hp->bufsiz);
  218.  
  219.         /* Setup DMA controller for tx */
  220.         setup_tx_dma(hp,hp->txdmabuf,length);
  221.  
  222.         /* select transmit interrupts to enable */
  223.         /* Allow DMA on chan */
  224.         outportb(DMA_MASK,DMA_ENABLE|hp->dmachan);
  225.  
  226.         /* reset CRC, Txint pend*/
  227.         wrtscc(hp->cardbase,cmd,R0,RES_Tx_CRC|RES_Tx_P);
  228.  
  229.         /* allow Underrun int only */
  230.         wrtscc(hp->cardbase,cmd,R15,TxUIE);
  231.  
  232.         /* Enable TX DMA */
  233.         wrtscc(hp->cardbase,cmd,R1,WT_RDY_ENAB|WT_FN_RDYFN|EXT_INT_ENAB);
  234.  
  235.         /* Send CRC on underrun */
  236.         wrtscc(hp->cardbase,cmd,R0,RES_EOM_L);
  237.  
  238.         /* packet going out now */
  239.         hp->tstate = ACTIVE;
  240.         break;
  241.     case DEFER:
  242.         /* we have deferred prev xmit attempt
  243.          * See Intel Microcommunications Handbook, p2-308
  244.          */
  245.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  246.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  247.         if((rdscc(hp->cardbase,cmd,R0) & DCD) != 0){
  248.             hp->tstate = DEFER;
  249.             tdelay(hp,100);
  250.             /* Defer until dcd transition or 100mS timeout */
  251.             wrtscc(hp->cardbase,CTL+hp->base,R15,CTSIE|DCDIE);
  252.             restore(i_state);
  253.             return;
  254.         }
  255.  
  256.         if((rand() & 0xff) > uchar(hp->persist)){
  257.             hp->tstate = DEFER;
  258.             tdelay(hp,hp->slotime);
  259.             restore(i_state);
  260.             return;
  261.         }
  262.         /* Assert RTS early minimize collision window */
  263.         wrtscc(hp->cardbase,cmd,R5,TxCRC_ENAB|RTS|Tx8);
  264.         rts(hp,ON);    /* Transmitter on */
  265.         hp->tstate = ST_TXDELAY;
  266.         tdelay(hp,hp->txdelay);
  267.         restore(i_state);
  268.         return;
  269.     } /* switch(hp->tstate) */
  270.  
  271.     restore(i_state);
  272. } /* a_exint() */
  273.  
  274. /* Receive interrupt handler for the A channel 
  275.  */
  276. static void
  277. a_rxint(hp)
  278. register struct pichan *hp;
  279. {
  280.     register int16 cmd;
  281.     register int16 bytecount;
  282.     char rse, i_state;
  283.     struct mbuf *bp;
  284.     struct phdr phdr;
  285.  
  286.     i_state = dirps();        /* disable interrupts */
  287.     hp->rxints++;
  288.     cmd = hp->base+CTL;
  289.  
  290.     rse = rdscc(hp->cardbase,cmd,R1); /* Get special condition bits from R1 */
  291.     if(rse & Rx_OVR)
  292.         hp->rstate = RXERROR;
  293.  
  294.     if(rse & END_FR){
  295.         /* If end of frame */
  296.         /* figure length of frame from 8237 */
  297.         outportb(DMA_RESETFF,0); /* reset firstlast ff */
  298.         bytecount = inportb(hp->dma_wcr);
  299.         bytecount += inportb(hp->dma_wcr) << 8;
  300.         /* Allow for the extra space for phdr */
  301.         bytecount = (hp->bufsiz - 1 - sizeof(struct phdr)) - bytecount;
  302.  
  303.         if((rse & CRC_ERR)||(hp->rstate > ACTIVE)||(bytecount < 10)){
  304.             if((bytecount >= 10) && (rse & CRC_ERR))
  305.                 hp->crcerr++; /* Ignore noise */
  306.  
  307.             if(hp->rstate == RXERROR)
  308.                 hp->rovers++;
  309.             /* Reset buffer pointers */
  310.             hp->rstate = ACTIVE;
  311.             setup_rx_dma(hp);
  312.         } else {
  313.             /* Here we have a valid frame */
  314.             /* Toss 2 crc bytes */
  315.             hp->rcvbuf->cnt = bytecount - 2;
  316.             /* "Can't fail" */
  317.             bp = pushdown(hp->rcvbuf,sizeof(phdr));
  318.             phdr.type = CL_AX25;
  319.             phdr.iface = hp->iface;
  320.             memcpy(bp->data,(char *)&phdr,sizeof(phdr));
  321.             hp->rcvbuf = NULLBUF;
  322.             enqueue(&Hopper,bp);       /* queue it in */
  323.             hp->rxframes++;
  324.  
  325.             /* packet queued - get buffer for next frame */
  326.             hp->rcvbuf = alloc_mbuf(hp->bufsiz + sizeof(phdr));
  327.             if(hp->rcvbuf != NULLBUF)
  328.                 /* Allow room for phdr */
  329.                 hp->rcvbuf->data += sizeof(struct phdr);
  330.             setup_rx_dma(hp);
  331.         } /* end good frame queued */
  332.     } /* end EOF check */
  333.  
  334.     wrtscc(hp->cardbase,hp->base+CTL,R0,ERR_RES);    /* error reset */
  335.     restore(i_state);
  336. }
  337.  
  338. void
  339. a_txint(hp)
  340. register struct pichan *hp;
  341. {
  342.     register int16 cmd;
  343.     char i_state;
  344.     int32 t,ca;
  345.  
  346.     i_state = dirps();
  347.     cmd = CTL+hp->base;
  348.  
  349.     switch(hp->tstate){
  350.     case IDLE:
  351.         /* Transmitter idle. Find a frame for transmission */
  352.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  353.             rts(hp,OFF);
  354.             restore(i_state);
  355.             return;
  356.         }
  357.         /* If a buffer to send, we drop thru here */
  358.     case DEFER:
  359.         /* we may have deferred prev xmit attempt */
  360.         /* Check DCD - debounce it
  361.          * See Intel Microcommunications Handbook, p2-308
  362.          */
  363.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  364.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  365.         if((rdscc(hp->cardbase,cmd,R0) & DCD) != 0){
  366.             hp->tstate = DEFER;
  367.             tdelay(hp,100);
  368.             /* defer until DCD transition or timeout */
  369.             wrtscc(hp->cardbase,cmd,R15,CTSIE|DCDIE);
  370.             restore(i_state);
  371.             return;
  372.         }
  373.  
  374.         if((rand() & 0xff) > uchar(hp->persist)){
  375.             hp->tstate = DEFER;
  376.             tdelay(hp,hp->slotime);
  377.             restore(i_state);
  378.             return;
  379.         }
  380.  
  381.         /* Assert RTS early minimize collision window */
  382.         wrtscc(hp->cardbase,cmd,R5,TxCRC_ENAB|RTS|Tx8);
  383.         rts(hp,ON);    /* Transmitter on */
  384.         hp->tstate = ST_TXDELAY;
  385.         tdelay(hp,hp->txdelay);
  386.         restore(i_state);
  387.         return;
  388.     default:
  389.         break;
  390.     } /* end switch(hp->state) */
  391.  
  392.     restore(i_state);
  393. } /*a_txint */
  394.  
  395. static void
  396. b_rxint(hp)
  397. register struct pichan *hp;
  398. {
  399.     register int16 cmd;
  400.     char rse, i_state;
  401.     struct mbuf *bp;
  402.     struct phdr phdr;
  403.  
  404.     i_state = dirps();        /* disable interrupts */
  405.     hp->rxints++;
  406.     cmd = CTL+hp->base;
  407.  
  408.     if((rdscc(hp->cardbase,cmd,R0)) & Rx_CH_AV){
  409.         /* there is a char to be stored
  410.          * read special condition bits before reading the data char
  411.          */
  412.         rse = rdscc(hp->cardbase,cmd,R1); /* get status byte from R1 */
  413.         if(rse & Rx_OVR){
  414.             /* Rx overrun - toss buffer */
  415.             /* reset buffer pointers */
  416.             hp->rcp = hp->rcvbuf->data;
  417.             hp->rcvbuf->cnt = 0;
  418.             hp->rstate = RXERROR;    /* set error flag */
  419.             hp->rovers++;
  420.         } else if(hp->rcvbuf->cnt >= hp->bufsiz - sizeof(struct phdr)){
  421.             /* Too large -- toss buffer */
  422.             /* reset buffer pointers */
  423.             hp->rcp = hp->rcvbuf->data;
  424.             hp->rcvbuf->cnt = 0;
  425.             hp->rstate = TOOBIG;    /* when set, chars are not stored */
  426.         }
  427.         /* ok, we can store the received character now */
  428.         if(hp->rstate == ACTIVE){    /* If no errors... */
  429.             *hp->rcp++ = rdscc(hp->cardbase,cmd,R8); /* char to rcv buff */
  430.             hp->rcvbuf->cnt++;           /* bump count */
  431.         } else {
  432.             /* got to empty FIFO */
  433.             (void) rdscc(hp->cardbase,cmd,R8);
  434.             wrtscc(hp->cardbase,cmd,R0,ERR_RES);    /* reset err latch */
  435.             hp->rstate = ACTIVE;
  436.         }
  437.     }
  438.  
  439.     if(rse & END_FR){
  440.         /* END OF FRAME -- Make sure Rx was active */
  441.         if(hp->rcvbuf->cnt > 0){
  442.             if((rse & CRC_ERR)||(hp->rstate > ACTIVE)||(hp->rcvbuf->cnt < 10)){
  443.                 if((hp->rcvbuf->cnt >= 10) && (rse & CRC_ERR))
  444.                     hp->crcerr++; /* Ignore noise */
  445.  
  446.                 hp->rcp = hp->rcvbuf->data;
  447.                 hp->rcvbuf->cnt = 0;
  448.             } else {
  449.                 /* Here we have a valid frame */
  450.                 hp->rcvbuf->cnt -= 2;  /* Toss 2 crc bytes */
  451.                 /* "Can't fail" */
  452.                 bp = pushdown(hp->rcvbuf,sizeof(phdr));
  453.                 phdr.type = CL_AX25;
  454.                 phdr.iface = hp->iface;
  455.                 memcpy(bp->data,(char *)&phdr,sizeof(phdr));
  456.                 enqueue(&Hopper,bp);       /* queue it in */
  457.                 hp->rxframes++;
  458.  
  459.                 /* packet queued - get buffer for next frame */
  460.                 hp->rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct phdr));
  461.                 if(hp->rcvbuf == NULLBUF){
  462.                     /* No memory - abort rx */
  463.                     wrtscc(hp->cardbase,cmd,R3,Rx8);
  464.                     restore(i_state);
  465.                     return;
  466.                 }
  467.                 hp->rcvbuf->data += sizeof(struct phdr);
  468.                 hp->rcp = hp->rcvbuf->data;
  469.                 hp->rcvbuf->cnt = 0;
  470.             } /* end good frame queued */
  471.         }  /* end check for active receive upon EOF */
  472.         hp->rstate = ACTIVE;    /* and clear error status */
  473.     } /* end EOF check */
  474.  
  475.     restore(i_state);
  476. }
  477.  
  478. static void
  479. b_txint(hp)
  480. register struct pichan *hp;
  481. {
  482.     register int16 cmd;
  483.     char i_state;
  484.     int c;
  485.  
  486.     i_state = dirps();
  487.     cmd = CTL+hp->base;
  488.  
  489.     if(hp->tstate != DEFER && hp->tstate)
  490.         hp->txints++;
  491.  
  492.     switch(hp->tstate){
  493.     case CRCOUT:
  494.         hp->tstate = FLAGOUT;
  495.         tdelay(hp,hp->squeldelay);
  496.         restore(i_state);
  497.         return;
  498.     case IDLE:
  499.         /* Transmitter idle. Find a frame for transmission */
  500.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  501.             /* Nothing to send - return to receive mode
  502.              * Tx OFF now - flag should have gone
  503.              */
  504.             rts(hp,OFF);
  505.             restore(i_state);
  506.             return;
  507.         }
  508.         /* If a buffer to send, we drop thru here */
  509.     case DEFER:        /* we may have deferred prev xmit attempt */
  510.         /* Check DCD - debounce it */
  511.         /* See Intel Microcommunications Handbook, p2-308 */
  512.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  513.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  514.         if((rdscc(hp->cardbase,cmd,R0) & DCD) != 0){
  515.             hp->tstate = DEFER;
  516.             tdelay(hp,100);
  517.             /* defer until DCD transition or timeout */
  518.             wrtscc(hp->cardbase,cmd,R15,CTSIE|DCDIE);
  519.             restore(i_state);
  520.             return;
  521.         }
  522.         /* p - persist calculation */
  523.         if(inportb(hp->cardbase+TMR0) > hp->persist){
  524.             inportb(hp->cardbase+TMR0); /* Discard MSB */
  525.             hp->tstate = DEFER;
  526.             tdelay(hp,hp->slotime);
  527.             restore(i_state);
  528.             return;
  529.         }
  530.         inportb(hp->cardbase+TMR0); /* Discard MSB */
  531.  
  532.         rts(hp,ON);   /* Transmitter on */
  533.         hp->tstate = ST_TXDELAY;
  534.         tdelay(hp,hp->txdelay);
  535.         restore(i_state);
  536.         return;
  537.  
  538.     case ACTIVE:
  539.         /* Here we are actively sending a frame */
  540.         if((c = PULLCHAR(&hp->sndbuf)) != -1){
  541.             /* next char is gone */
  542.             wrtscc(hp->cardbase,cmd,R8,c);
  543.             /* stuffing a char satisfies Interrupt condition */
  544.         } else {
  545.             /* No more to send */
  546.             free_p(hp->sndbuf);
  547.             if((rdscc(hp->cardbase,cmd,R0) & 0x40)){
  548.                 /* Did we underrun? */
  549.                 /* unexpected underrun */
  550.                 hp->tunders++;
  551.                 wrtscc(hp->cardbase,cmd,R0,SEND_ABORT);
  552.                 hp->tstate = FLAGOUT;
  553.                 tdelay(hp,hp->squeldelay);
  554.                 restore(i_state);
  555.                 return;
  556.             }
  557.             hp->tstate = UNDERRUN; /* Now we expect to underrun */
  558.             /* Send flags on underrun */
  559.             if(hp->speed){ /* If externally clocked */
  560.                 wrtscc(hp->cardbase,cmd,R10,CRCPS|NRZI);
  561.             } else {
  562.                 wrtscc(hp->cardbase,cmd,R10,CRCPS);
  563.             }
  564.             wrtscc(hp->cardbase,cmd,R0,RES_Tx_P); /* reset Tx Int Pend */
  565.         }
  566.         restore(i_state);
  567.         return;     /* back to wait for interrupt */
  568.     } /* end switch */
  569.     restore(i_state);
  570. }
  571.  
  572. /* Pi SIO External/Status interrupts (for the B channel)
  573.  * This can be caused by a receiver abort, or a Tx UNDERRUN/EOM.
  574.  * Receiver automatically goes to Hunt on an abort.
  575.  *
  576.  * If the Tx Underrun interrupt hits, change state and
  577.  * issue a reset command for it, and return.
  578.  */
  579. static void
  580. b_exint(hp)
  581. register struct pichan *hp;
  582. {
  583.     char st, i_state;
  584.     register int16 cmd;
  585.     char c;
  586.  
  587.     cmd = CTL+hp->base;
  588.     i_state = dirps();        /* disable interrupts */
  589.     hp->exints++;
  590.     st = rdscc(hp->cardbase,cmd,R0);     /* Fetch status */
  591.     /* reset external status latch */
  592.     wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  593.  
  594.  
  595.     switch(hp->tstate){
  596.     case ACTIVE:    /* Unexpected underrun */
  597.         free_p(hp->sndbuf);
  598.         wrtscc(hp->cardbase,cmd,R0,SEND_ABORT);
  599.         hp->tstate = FLAGOUT;
  600.         hp->tunders++;
  601.         tdelay(hp,hp->squeldelay);
  602.         restore(i_state);
  603.         return;
  604.     case UNDERRUN:
  605.         hp->tstate = CRCOUT;
  606.         restore(i_state);
  607.         return;
  608.     case FLAGOUT: 
  609.         /* Find a frame for transmission */
  610.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  611.             /* Nothing to send - return to receive mode
  612.              * Tx OFF now - flag should have gone
  613.              */
  614.             rts(hp,OFF);
  615.             hp->tstate = IDLE;
  616.             restore(i_state);
  617.             return;
  618.         }
  619.         /* Get next char to send */
  620.         pullup(&hp->sndbuf,&c,1);    /* one char at a time */
  621.         wrtscc(hp->cardbase,cmd,R0,RES_Tx_CRC);/* reset for next frame */
  622.  
  623.         /* Send abort on underrun */
  624.         if(hp->speed){ /* If externally clocked */
  625.             wrtscc(hp->cardbase,cmd,R10,CRCPS|NRZI|ABUNDER);
  626.         } else {
  627.             wrtscc(hp->cardbase,cmd,R10,CRCPS|ABUNDER);
  628.         }
  629.  
  630.         wrtscc(hp->cardbase,cmd,R8,c);    /* First char out now */
  631.         wrtscc(hp->cardbase,cmd,R0,RES_EOM_L);/* Reset end of message latch */
  632.  
  633.         /* select transmit interrupts to enable */
  634.  
  635.         wrtscc(hp->cardbase,cmd,R15,TxUIE);    /* allow Underrun int only */
  636.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  637.         wrtscc(hp->cardbase,cmd,R1,TxINT_ENAB|EXT_INT_ENAB);  /* Tx/Extern ints on */
  638.  
  639.         hp->tstate = ACTIVE;    /* char going out now */
  640.         restore(i_state);
  641.         return;
  642.  
  643.     case DEFER:
  644.         /* Check DCD - debounce it
  645.          * See Intel Microcommunications Handbook, p2-308
  646.          */
  647.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  648.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  649.         if((rdscc(hp->cardbase,cmd,R0) & DCD) != 0){
  650.             hp->tstate = DEFER;
  651.             tdelay(hp,100);
  652.             /* defer until DCD transition or timeout */
  653.             wrtscc(hp->cardbase,cmd,R15,CTSIE|DCDIE);
  654.             restore(i_state);
  655.             return;
  656.         }
  657.         /* p - persist calculation */
  658.         if(inportb(hp->cardbase+TMR0) > hp->persist){
  659.             inportb(hp->cardbase+TMR0); /* Discard MSB */
  660.             hp->tstate = DEFER;
  661.             tdelay(hp,hp->slotime);
  662.             restore(i_state);
  663.             return;
  664.         }
  665.         inportb(hp->cardbase+TMR0); /* Discard MSB */
  666.  
  667.         rts(hp,ON);   /* Transmitter on */
  668.         hp->tstate = ST_TXDELAY;
  669.         tdelay(hp,hp->txdelay);
  670.         restore(i_state);
  671.         return;
  672.  
  673.     case ST_TXDELAY:
  674.  
  675.         /* Get next char to send */
  676.         pullup(&hp->sndbuf,&c,1);     /* one char at a time */
  677.         wrtscc(hp->cardbase,cmd,R0,RES_Tx_CRC);/* reset for next frame */
  678.  
  679.         /* Send abort on underrun */
  680.         if(hp->speed){ /* If externally clocked */
  681.             wrtscc(hp->cardbase,cmd,R10,CRCPS|NRZI|ABUNDER);
  682.         } else {
  683.             wrtscc(hp->cardbase,cmd,R10,CRCPS|ABUNDER);
  684.         }
  685.  
  686.         wrtscc(hp->cardbase,cmd,R8,c);    /* First char out now */
  687.         wrtscc(hp->cardbase,cmd,R0,RES_EOM_L);/* Reset end of message latch */
  688.  
  689.         /* select transmit interrupts to enable */
  690.  
  691.         wrtscc(hp->cardbase,cmd,R15,TxUIE);    /* allow Underrun int only */
  692.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  693.         /* Tx/Extern ints on */
  694.         wrtscc(hp->cardbase,cmd,R1,TxINT_ENAB|EXT_INT_ENAB);
  695.  
  696.         hp->tstate = ACTIVE;    /* char going out now */
  697.         restore(i_state);
  698.         return;
  699.     }
  700.  
  701.     /* Receive Mode only
  702.      * This triggers when hunt mode is entered, & since an ABORT
  703.      * automatically enters hunt mode, we use that to clean up
  704.      * any waiting garbage
  705.      */
  706.     if((hp->rstate == ACTIVE) && (st & BRK_ABRT)){
  707.         (void) rdscc(hp->cardbase,cmd,R8);
  708.         (void) rdscc(hp->cardbase,cmd,R8);
  709.         (void) rdscc(hp->cardbase,cmd,R8);
  710.         hp->rcp = hp->rcvbuf->data;
  711.         hp->rcvbuf->cnt = 0;          /* rewind on DCD transition */
  712.     }
  713.     restore(i_state);
  714. }
  715.  
  716. /* SET Transmit or Receive Mode
  717.  * Set RTS (request-to-send) to modem on Transmit
  718.  */
  719. static void
  720. rts(hp,x)
  721. register struct pichan *hp;
  722. int16 x;
  723. {
  724.     int16 tc;
  725.     long br;
  726.     int16 cmd;
  727.  
  728.     cmd = CTL+hp->base;
  729.  
  730.     /* Reprogram BRG and turn on transmitter to send flags */
  731.     if(x == ON){    /* Turn Tx ON and Receive OFF */
  732.         /* Exints off first to avoid abort int */
  733.         wrtscc(hp->cardbase,cmd,R15,0);
  734.         wrtscc(hp->cardbase,cmd,R3,Rx8);    /* Rx off */
  735.         hp->rstate = IDLE;
  736.         if(cmd & 2){ /* if channel a */
  737.             /* Set up for TX dma */
  738.             wrtscc(hp->cardbase,cmd,R1,WT_FN_RDYFN|EXT_INT_ENAB);
  739.         } else {
  740.             wrtscc(hp->cardbase,cmd,R1,0);    /* No interrupts */
  741.         }
  742.         if(hp->speed){            /* if internally clocked */
  743.             br = hp->speed;        /* get desired speed */
  744.             tc = (XTAL/br)-2;    /* calc 1X BRG divisor */
  745.             wrtscc(hp->cardbase,cmd,R12,tc&0xFF);     /* lower byte */
  746.             wrtscc(hp->cardbase,cmd,R13,(tc>>8)&0xFF);/* upper byte */
  747.         }
  748.         wrtscc(hp->cardbase,cmd,R5,TxCRC_ENAB|RTS|TxENAB|Tx8|DTR);
  749.         /* Transmitter now on */
  750.     } else {    /* Tx OFF and Rx ON */
  751.         hp->tstate = IDLE;
  752.         wrtscc(hp->cardbase,cmd,R5,Tx8|DTR);     /*  TX off */
  753.  
  754.         if(hp->speed){        /* if internally clocked */
  755.             /* Reprogram BRG for 32x clock for receive DPLL */
  756.             /* BRG off, keep Pclk source */
  757.             wrtscc(hp->cardbase,cmd,R14,BRSRC);
  758.             br = hp->speed;            /* get desired speed */
  759.             /* calc 32X BRG divisor */
  760.             tc = ((XTAL/32)/br)-2;
  761.             wrtscc(hp->cardbase,cmd,R12,tc&0xFF);    /* lower byte */
  762.             wrtscc(hp->cardbase,cmd,R13,(tc>>8)&0xFF);/* upper byte */
  763.             /* SEARCH mode, BRG source */
  764.             wrtscc(hp->cardbase,cmd,R14,BRSRC|SEARCH);
  765.             /* Enable the BRG */
  766.             wrtscc(hp->cardbase,cmd,R14,BRSRC|BRENABL);
  767.         }
  768.         /* Now, turn on the receiver and hunt for a flag */
  769.         wrtscc(hp->cardbase,cmd,R3,RxENABLE|RxCRC_ENAB|Rx8);
  770.         hp->rstate = ACTIVE;        /* Normal state */
  771.  
  772.         if(cmd & 2){/* if channel a */
  773.             setup_rx_dma(hp);
  774.         } else {
  775.             /* reset buffer pointers */
  776.             hp->rcp = hp->rcvbuf->data;
  777.             hp->rcvbuf->cnt = 0;
  778.             wrtscc(hp->cardbase,cmd,R1,(INT_ALL_Rx|EXT_INT_ENAB));
  779.         }
  780.         wrtscc(hp->cardbase,cmd,R15,BRKIE);        /* allow ABORT int */
  781.     }
  782. }
  783.  
  784. void
  785. setup_rx_dma(hp)
  786. register struct pichan *hp;
  787. {
  788.     unsigned buf_offset, buf_segment;
  789.     int cmd;
  790.     long longseg, dma_abs, dma_page;
  791.     char i_state;
  792.  
  793.     i_state = dirps();        /* disable interrupts */
  794.  
  795.     cmd = hp->base+CTL;
  796.  
  797.     if(!hp->rcvbuf){
  798.         /* No rx buffer available */
  799.         restore(i_state);
  800.         return;
  801.     }
  802.  
  803.     /* Calculate high order 4 bits of the buffer area and store
  804.      *    them in the DMA page register
  805.      */
  806.     buf_offset = FP_OFF(hp->rcvbuf->data);
  807.     buf_segment= FP_SEG(hp->rcvbuf->data);
  808.     longseg = (long) buf_segment;
  809.     dma_abs = (longseg << 4) + (long) buf_offset;
  810.     dma_page = dma_abs >> 16;
  811.  
  812.     if(((dma_abs + hp->bufsiz -1) >> 16) != dma_page)
  813.         tprintf("PI: ERROR - RX DMA page boundary violation\n");
  814.  
  815.     /* Get ready for RX DMA */
  816.     wrtscc(hp->cardbase,cmd,R1,WT_FN_RDYFN|WT_RDY_RT|INT_ERR_Rx|EXT_INT_ENAB);
  817.     outportb(DMA_MASK, DMA_DISABLE|hp->dmachan); /* Disable DMA chan */
  818.     /* Set DMA mode register to single transfers, incrementing address,
  819.      *    auto init, writes
  820.      */
  821.     outportb(DMA_MODE,DMA_RX_MODE|hp->dmachan);
  822.  
  823.     outportb(hp->page_addr,dma_page);/* Store in  64K DMA page */
  824.     outportb(DMA_RESETFF,0);     /* reset byte pointer flipflop */
  825.     /* Output buffer start (dest) address */
  826.     outportb(hp->dma_dest,dma_abs);
  827.     outportb(hp->dma_dest,dma_abs >> 8);
  828.     /* output DMA maximum byte count */
  829.     outportb(hp->dma_wcr,hp->bufsiz - 1 - sizeof(struct phdr));
  830.     outportb(hp->dma_wcr, (hp->bufsiz - 1 - sizeof(struct phdr)) >> 8);
  831.     /* Unmask channel 1 (start DMA) */
  832.     outportb(DMA_MASK, DMA_ENABLE|hp->dmachan); /* Enable DMA chan */
  833.  
  834.     /* If a packet is already coming in, this line is supposed
  835.      *    to mess up the crc to avoid receiving a partial packet
  836.      */
  837.     wrtscc(hp->cardbase,cmd,R0,RES_Rx_CRC);
  838.  
  839.     /* Enable RX dma */
  840.     wrtscc(hp->cardbase,cmd,R1,WT_RDY_ENAB|WT_FN_RDYFN|WT_RDY_RT|INT_ERR_Rx|EXT_INT_ENAB);
  841.  
  842.     restore(i_state);
  843. }
  844.  
  845. void
  846. setup_tx_dma(hp,buffer,length)
  847. struct pichan *hp;
  848. char *buffer;
  849. int length;
  850. {
  851.     unsigned buf_offset, buf_segment;
  852.     long longseg, dma_abs, dma_page;
  853.     char i_state;
  854.  
  855.     i_state = dirps();        /* disable interrupts */
  856.  
  857.     /* Calculate high order 4 bits of the buffer area and store
  858.      *    them in the DMA page register
  859.      */
  860.  
  861.     buf_offset = FP_OFF(buffer);
  862.     buf_segment= FP_SEG(buffer);
  863.     longseg = (long) buf_segment;
  864.     dma_abs = (longseg << 4) + (long) buf_offset;
  865.     dma_page = dma_abs >> 16;
  866.  
  867.     outportb(DMA_MASK, DMA_DISABLE|hp->dmachan); /* Disable DMA chan */
  868.     if(((dma_abs + length) >> 16) != dma_page)
  869.         tprintf("PI: ERROR - TX DMA page boundary violation\n");
  870.     --length;     /* Adjust length for DMA chip */
  871.     /* Set DMA mode register to single transfers, incrementing address,
  872.      *    no auto init, reads
  873.       */
  874.     outportb(DMA_MODE,DMA_TX_MODE|hp->dmachan);
  875.  
  876.     outportb(hp->page_addr,dma_page); /* Store in 64K DMA page */
  877.     outportb(DMA_RESETFF,0);    /* reset byte pointer flipflop */
  878.     outportb(hp->dma_dest,dma_abs);    /* Output buffer start (source) address */
  879.     outportb(hp->dma_dest,dma_abs >> 8);
  880.     /* output byte count */
  881.     outportb(hp->dma_wcr,length);
  882.     outportb(hp->dma_wcr, (length) >> 8);
  883.  
  884.     restore(i_state);
  885. }
  886.  
  887. /* Initialize pi controller parameters */
  888. static int
  889. scc_init(hp)
  890. register struct pichan *hp;
  891. {
  892.     int16 tc;
  893.     long br;
  894.     char i_state;
  895.     register int16 cmd;
  896.  
  897.     /* Initialize 8530 channel for SDLC operation */
  898.  
  899.     cmd = CTL+hp->base;
  900. #ifdef    notdef
  901.     tprintf("Pi: Initializing Channel %c - Base = %x\n",cmd&2?'A':'B',cmd&~CTL);
  902. #endif
  903.     i_state = dirps();
  904.  
  905.     switch(cmd & 2){
  906.     case 2:
  907.         wrtscc(hp->cardbase,cmd,R9,CHRA);    /* Reset channel A */
  908.         wrtscc(hp->cardbase,cmd,R2,0xff); /* Initialize interrupt vector */
  909.         break;
  910.     case 0:
  911.         wrtscc(hp->cardbase,cmd,R9,CHRB);    /* Reset channel B */
  912.         break;
  913.     }
  914.  
  915.     /* Deselect all Rx and Tx interrupts */
  916.     wrtscc(hp->cardbase,cmd,R1,0);
  917.  
  918.     /* Turn off external interrupts (like CTS/CD) */
  919.     wrtscc(hp->cardbase,cmd,R15,0);
  920.  
  921.     /* X1 clock, SDLC mode */
  922.     wrtscc(hp->cardbase,cmd,R4,SDLC|X1CLK);
  923.  
  924.     /* Now some misc Tx/Rx parameters */
  925.     /* CRC PRESET 1, NRZI Mode */
  926.     if(hp->speed){
  927.         wrtscc(hp->cardbase,cmd,R10,CRCPS|NRZI);
  928.         /* Tx Clk from BRG. Rcv Clk from DPLL, TRxC pin outputs DPLL */
  929.         wrtscc(hp->cardbase,cmd,R11,TCBR|RCDPLL|TRxCDP|TRxCOI);
  930.     } else {
  931.         wrtscc(hp->cardbase,cmd,R10,CRCPS);
  932.         /* Tx Clk from Trxcl. Rcv Clk from Rtxcl, TRxC pin is input */
  933.         wrtscc(hp->cardbase,cmd,R11,TCTRxCP);
  934.     }
  935.  
  936.     /* Null out SDLC start address */
  937.     wrtscc(hp->cardbase,cmd,R6,0);
  938.  
  939.     /* SDLC flag */
  940.     wrtscc(hp->cardbase,cmd,R7,FLAG);
  941.  
  942.     /* Set up the Transmitter but don't enable it
  943.      *  DTR, 8 bit TX chars only - TX NOT ENABLED
  944.      */
  945.     wrtscc(hp->cardbase,cmd,R5,Tx8|DTR);
  946.  
  947.     /* Receiver - intial setup only - more later */
  948.     wrtscc(hp->cardbase,cmd,R3,Rx8);            /* 8 bits/char */
  949.  
  950.     /* Setting up BRG now - turn it off first */
  951.     wrtscc(hp->cardbase,cmd,R14,BRSRC);         /* BRG off, but keep Pclk source */
  952.  
  953.     /* set the 32x time constant for the BRG in Receive mode */
  954.  
  955.     if(hp->speed){
  956.         br = hp->speed;     /* get desired speed */
  957.         tc = ((XTAL/32)/br)-2;    /* calc 32X BRG divisor */
  958.     } else {
  959.         tc = 14;
  960.     }
  961.  
  962.     wrtscc(hp->cardbase,cmd,R12,tc&0xFF);      /* lower byte */
  963.     wrtscc(hp->cardbase,cmd,R13,(tc>>8)&0xFF); /* upper byte */
  964.  
  965.     /* Following subroutine sets up and ENABLES the receiver */
  966.     rts(hp,OFF);           /* TX OFF and RX ON */
  967.  
  968.     if(hp->speed){
  969.         /* DPLL frm BRG, BRG src PCLK */
  970.         wrtscc(hp->cardbase,cmd,R14,BRSRC|SSBR);
  971.     } else {
  972.         /* DPLL frm rtxc,BRG src PCLK */
  973.         wrtscc(hp->cardbase,cmd,R14,BRSRC|SSRTxC);
  974.     }
  975.     wrtscc(hp->cardbase,cmd,R14,BRSRC|SEARCH); /* SEARCH mode, keep BRG source */
  976.     wrtscc(hp->cardbase,cmd,R14,BRSRC|BRENABL);/* Enable the BRG */
  977.  
  978.     if(!(cmd & 2)) /* if channel b */
  979.         wrtscc(hp->cardbase,cmd,R1,(INT_ALL_Rx|EXT_INT_ENAB));
  980.  
  981.     wrtscc(hp->cardbase,cmd,R15,BRKIE);        /* ABORT int */
  982.  
  983.     /* Now, turn on the receiver and hunt for a flag */
  984.     wrtscc(hp->cardbase,cmd,R3,RxENABLE|RxCRC_ENAB|Rx8);
  985.  
  986.     restore(i_state);
  987.     return 0;
  988. }
  989.  
  990. /* Process to recover from ibuffails.
  991.  * This could be done in the function network() in config.c,
  992.  * to save a context switch.  I put it here so the driver would
  993.  * be more self contained.
  994. */
  995. void
  996. buf_recover(unused,b,a)
  997. int unused;
  998. void *b;    /* Unused */
  999. void *a;    /* Unused */
  1000. {
  1001.     struct pichan *hp0, *hp1;
  1002.     char i_state;
  1003.     int i;
  1004.  
  1005.     for(;;){
  1006.         pwait(NULL);
  1007.  
  1008.         for(i=0; i<pinbr; i++){ /* for each card */
  1009.             hp0 = &Pichan[i];
  1010.             hp1 = &Pichan[i + 1];
  1011.             if(!hp0->rcvbuf){ /* No rx buffer allocated */
  1012.                 i_state = dirps();
  1013.                 hp0->rcvbuf = alloc_mbuf(hp0->bufsiz + sizeof(struct phdr));
  1014.                 if(hp0->rcvbuf != NULLBUF)
  1015.                     hp0->rcvbuf->data += sizeof(struct phdr);
  1016.                 restore(i_state);
  1017.                 setup_rx_dma(hp0);
  1018.             }
  1019.             i_state = dirps();
  1020.             if(!hp1->rcvbuf && (hp1->rstate == ACTIVE)){
  1021.                 /* No rx buf allocated */
  1022.                 if((hp1->rcvbuf = alloc_mbuf(hp1->bufsiz+sizeof(struct phdr))) != NULL){
  1023.                     hp1->rcvbuf->data += sizeof(struct phdr);
  1024.                     hp1->rcp = hp1->rcvbuf->data;
  1025.                     hp1->rcvbuf->cnt = 0;
  1026.                     wrtscc(hp1->cardbase,CTL+hp1->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
  1027.                 }
  1028.             }
  1029.             restore(i_state);
  1030.         }
  1031.     }
  1032. }
  1033.  
  1034. /* Attach a PI interface to the system
  1035.  * argv[0]: hardware type, must be "pi"
  1036.  * argv[1]: I/O address, e.g., "0x300"
  1037.  * argv[2]: vector, e.g., "2"
  1038.  * argv[3]: dma channel (1..3)
  1039.  * argv[4]: mode, must be:
  1040.  *        "ax25" (AX.25 UI frame format)
  1041.  * argv[5]: interface label, e.g., "pi0"
  1042.  * argv[6]: receiver packet buffer size in bytes
  1043.  * argv[7]: maximum transmission unit, bytes
  1044.  * argv[8]: channel A interface speed, e.g, "1200", 0 = ext. clock
  1045.  * argv[9]: channel B interface speed
  1046.  * argv[10]: First IP address, optional (defaults to Ip_addr);
  1047.  * argv[11]: Second IP address, optional (defaults to Ip_addr);
  1048.  */
  1049. int
  1050. pi_attach(argc,argv)
  1051. int argc;
  1052. char *argv[];
  1053. {
  1054.     struct mbuf *bp;
  1055.     extern void refiq();
  1056.     register struct iface *if_pca,*if_pcb;
  1057.     struct pichan *hp;
  1058.     int dev;
  1059.     char i_state;
  1060.     int n;
  1061.  
  1062.     refiq(); /* replenish interrupt buffer pool (in mbuf.c) */
  1063.     set_acc_delay();
  1064.     /* Quick check to make sure args are good and mycall is set */
  1065.     if(strcmp(argv[4],"ax25") != 0){
  1066.         tprintf("PI: Mode %s unknown for interface %s\n",
  1067.             argv[4],argv[5]);
  1068.         return -1;
  1069.     }
  1070.     if(if_lookup(argv[5]) != NULLIF){
  1071.         tprintf("PI: Interface %s already exists\n",argv[5]);
  1072.         return -1;
  1073.     }
  1074.     if(Mycall[0] == '\0'){
  1075.         tprintf("PI: Set mycall first\n");
  1076.         return -1;
  1077.     }
  1078.     /* Note: each card must have a unique address, IRQ and DMA */
  1079.  
  1080.     if(pinbr >= PIMAX){
  1081.         tprintf("PI: Maximum of %d PI cards supported\n",PIMAX);
  1082.         return -1;
  1083.     }
  1084.     dev = pinbr++;
  1085.  
  1086.     /* Initialize hardware-level control structure */
  1087.     Pi[dev].addr = htoi(argv[1]);
  1088.     Pi[dev].vec = htoi(argv[2]);
  1089.  
  1090.     /* Set up counter chip */
  1091.     /* 500 uS square wave */
  1092.     outportb(Pi[dev].addr+TMRCMD, SC0|LSB_MSB|MODE3);
  1093.     for(n=0; n<5;n++) /* satisfy access time restriction */
  1094.         ;
  1095.     outportb(Pi[dev].addr+TMR0, 922 & 0xFF); 
  1096.     for(n=0; n<5;n++) /* satisfy access time restriction */
  1097.         ;
  1098.     outportb(Pi[dev].addr+TMR0, 922 >> 8);
  1099.     for(n=0; n<5;n++) /* satisfy access time restriction */
  1100.         ;
  1101.  
  1102.     /* Save original interrupt vector */
  1103.     Pi[dev].oldvec = getirq(Pi[dev].vec);
  1104.  
  1105.     /* Set new interrupt vector */
  1106.     if(setirq(Pi[dev].vec,pihandle[dev]) == -1){
  1107.         tprintf("PI: IRQ %u out of range\n",Pi[dev].vec);
  1108.         pinbr--;
  1109.         return -1;
  1110.     }
  1111.  
  1112.     if((atoi(argv[3]) < 1) || (atoi(argv[3]) > 3)){
  1113.         tprintf("PI: DMA %d out of range\n",atoi(argv[3]));
  1114.         pinbr--;
  1115.         return -1;
  1116.     }
  1117.  
  1118.     /* Create interface structures and fill in details */
  1119.     if_pca = (struct iface *)callocw(1,sizeof(struct iface));
  1120.     if_pcb = (struct iface *)callocw(1,sizeof(struct iface));
  1121.  
  1122.     if_pca->addr = if_pcb->addr = Ip_addr;
  1123.     if(argc > 10)
  1124.         if_pca->addr = resolve(argv[10]);
  1125.     if(argc > 11)
  1126.         if_pcb->addr = resolve(argv[11]);
  1127.  
  1128.     if(if_pca->addr == 0 || if_pcb->addr == 0){
  1129.         tprintf("PI: No IP address");
  1130.         free((char *)if_pca);
  1131.         free((char *)if_pcb);
  1132.         return -1;
  1133.     }
  1134.     /* Append "a" to interface associated with A channel */
  1135.     if_pca->name = malloc((unsigned)strlen(argv[5])+2);
  1136.     strcpy(if_pca->name,argv[5]);
  1137.     strcat(if_pca->name,"a");
  1138.     /* Append "b" to interface associated with B channel */
  1139.     if_pcb->name = malloc((unsigned)strlen(argv[5])+2);
  1140.     strcpy(if_pcb->name,argv[5]);
  1141.     strcat(if_pcb->name,"b");
  1142.  
  1143.     if_pcb->mtu = if_pca->mtu = atoi(argv[7]);
  1144.     if_pcb->type = if_pca->type = CL_AX25;
  1145.     if_pcb->ioctl = if_pca->ioctl = pi_ctl;
  1146.     if_pca->dev = 2*dev;            /* pi0a */
  1147.     if_pcb->dev = 2*dev + 1;        /* pi0b */
  1148.     if_pcb->stop = if_pca->stop = pi_stop;
  1149.     if_pcb->output = if_pca->output = ax_output;
  1150.     if_pcb->raw = if_pca->raw = pi_raw;
  1151.  
  1152.     if(strcmp(argv[4],"ax25") == 0){
  1153.         /* Must be true, was checked at top */
  1154.         if_pcb->send = if_pca->send = ax_send;
  1155.         if(if_pcb->hwaddr == NULLCHAR)
  1156.             if_pcb->hwaddr = mallocw(AXALEN);
  1157.         memcpy(if_pcb->hwaddr,Mycall,AXALEN);
  1158.         if(if_pcb->ipcall == NULLCHAR)
  1159.             if_pcb->ipcall = mallocw(AXALEN);
  1160.         memcpy(if_pcb->ipcall,Mycall,AXALEN);
  1161.         if(if_pca->hwaddr == NULLCHAR)
  1162.             if_pca->hwaddr = mallocw(AXALEN);
  1163.         memcpy(if_pca->hwaddr,Mycall,AXALEN);
  1164.         if(if_pca->ipcall == NULLCHAR)
  1165.             if_pca->ipcall = mallocw(AXALEN);
  1166.         memcpy(if_pca->ipcall,Mycall,AXALEN);
  1167.     }
  1168.     /* Link em in to the interface chain */
  1169.     if_pca->next = if_pcb;
  1170.     if_pcb->next = Ifaces;
  1171.     Ifaces = if_pca;
  1172.  
  1173.     /* set params in pichan table for CHANNEL B */
  1174.     hp = &Pichan[2*dev+1];            /* pi1 is offset 1 */
  1175.     hp->dmachan = 0; /* Channel B does not have dma */
  1176.     hp->cardbase = Pi[dev].addr;
  1177.     hp->iface = if_pcb;
  1178.     hp->stata = Pi[dev].addr + CHANA + CTL;    /* permanent status */
  1179.     hp->statb = Pi[dev].addr + CHANB + CTL;    /* addrs for CHANA/B*/
  1180.     hp->speed = (int16)atoi(argv[9]);
  1181.     hp->base = Pi[dev].addr + CHANB;
  1182.     hp->bufsiz = atoi(argv[6]);
  1183.     hp->tstate = IDLE;
  1184.     /* default channel access Params */
  1185.     hp->txdelay = 30;        /* 300 Ms */
  1186.     hp->persist = 128;        /* 50% persistence */
  1187.     hp->slotime = 30;        /* 300 Ms */
  1188.     hp->squeldelay = 3;        /* 30 Ms */
  1189.  
  1190.     wrtscc(hp->cardbase,CTL+hp->stata,R9,FHWRES);     /* Hardware reset */
  1191.                         /* one time only */
  1192.     /* Disable interrupts with Master interrupt ctrl reg */
  1193.     wrtscc(hp->cardbase,CTL+hp->stata,R9,0);
  1194.  
  1195.     scc_init(hp);
  1196.  
  1197.     /* Pre-allocate a receive buffer */
  1198.     i_state = dirps();
  1199.     hp->rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct phdr));
  1200.     restore(i_state);
  1201.     if(hp->rcvbuf == NULLBUF){
  1202.         /* No memory, abort receiver */
  1203.         tprintf("PI: No memory available for receive buffers\n");
  1204.         /* Restore original interrupt vector */
  1205.         setirq(Pi[dev].vec,Pi[dev].oldvec);
  1206.         pinbr--;
  1207.         return -1;
  1208.     }
  1209.     hp->rcvbuf->data += sizeof(struct phdr);
  1210.     hp->rcp = hp->rcvbuf->data;
  1211.     hp->rcvbuf->cnt = 0;
  1212.     hp->sndq = NULLBUF;
  1213.  
  1214.     /* set params in pichan table for CHANNEL A */
  1215.     hp = &Pichan[2*dev];    /* pi0a is offset 0 */
  1216.     hp->dmachan = (unsigned char)atoi(argv[3]);
  1217.     /* Figure out where the dma page register is. */
  1218.     if(hp->dmachan < 8 && hp->dmachan >= 0){
  1219.         hp->page_addr = Page_regs[hp->dmachan];
  1220.     } else {
  1221.         printf("PI: DMA channel %d out of range\n",hp->dmachan);
  1222.         free_p(hp->rcvbuf);
  1223.         /* Restore original interrupt vector */
  1224.         setirq(Pi[dev].vec,Pi[dev].oldvec);
  1225.         pinbr--;
  1226.         return -1;
  1227.     }
  1228.  
  1229.     hp->dma_dest = hp->dmachan * 2;
  1230.     hp->dma_wcr = hp->dma_dest + 1;
  1231.  
  1232.     hp->cardbase = Pi[dev].addr;
  1233.     hp->iface = if_pca;
  1234.     hp->speed = (int16)atoi(argv[8]);
  1235.     hp->base = Pi[dev].addr + CHANA;
  1236.     hp->bufsiz = atoi(argv[6]);
  1237.     hp->tstate = IDLE;
  1238.     /* default channel access Params */
  1239.     hp->txdelay = 15;        /* 15 mS */
  1240.     hp->persist = 128;        /* 50% persistence */
  1241.     hp->slotime = 15;        /* 15 mS */
  1242.     hp->squeldelay = 1;        /* 1 mS */
  1243.     newproc("buf_recover",256,buf_recover,0,hp,NULL,0);
  1244.  
  1245.     /* Pre-allocate a receive buffer */
  1246.     /* buffer is allocated with ints off */
  1247.     i_state = dirps();
  1248.     hp->rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct phdr));
  1249.     restore(i_state);
  1250.     if(hp->rcvbuf == NULLBUF){
  1251.         /* No memory, abort receiver */
  1252.         tprintf("PI: No memory available for receive buffers\n");
  1253.         /* Restore original interrupt vector */
  1254.         setirq(Pi[dev].vec,Pi[dev].oldvec);
  1255.         pinbr--;
  1256.         return -1;
  1257.     }
  1258.     hp->rcvbuf->data += sizeof(struct phdr);
  1259.     hp->rcvbuf->cnt = 0;
  1260.     hp->sndq = NULLBUF;
  1261.  
  1262.     /* Get a buffer for tx which does not cross a dma boundary */
  1263.     /* buffer is allocated with ints off */
  1264.     i_state = dirps();
  1265.     bp = alloc_mbuf(hp->bufsiz);
  1266.     if(bp != NULLBUF)
  1267.         hp->txdmabuf = bp->data;
  1268.     else
  1269.         hp->txdmabuf = NULLCHAR;
  1270.     restore(i_state);
  1271.     if(!hp->txdmabuf)
  1272.         tprintf("PI: No memory available for transmit buffer");
  1273.  
  1274.     scc_init(hp);
  1275.     /* master interrupt enable */
  1276.     wrtscc(hp->cardbase,CTL+hp->base,R9,MIE|NV);
  1277.  
  1278.     /* Enable interrupt */
  1279.     maskon(Pi[dev].vec);
  1280.  
  1281.     return 0;
  1282. }
  1283.  
  1284. /* Shut down interface */
  1285. int
  1286. pi_stop(iface)
  1287. struct iface *iface;
  1288. {
  1289.     int16 dev;
  1290.     struct pichan *hp;
  1291.  
  1292.     dev = iface->dev;
  1293.     if(dev & 1) /* Because there are 2 devices per card */
  1294.         return 0;
  1295.     dev >>= 1;        /* Convert back into pi number */
  1296.     hp = &Pichan[2*dev];    /* pi0a is offset 0 */
  1297.  
  1298.     outportb(DMA_MASK, DMA_DISABLE|hp->dmachan); /* Disable DMA channel */
  1299.  
  1300.     /* Turn off interrupts */
  1301.     maskoff(Pi[dev].vec);
  1302.  
  1303.     /* Restore original interrupt vector */
  1304.     setirq(Pi[dev].vec,Pi[dev].oldvec);
  1305.  
  1306.     /* Force hardware reset */
  1307.     wrtscc(((struct pichan *)(&Pichan[2*dev]))->cardbase,
  1308.         CTL+Pi[dev].addr + CHANA,R9,FHWRES);
  1309.  
  1310.     return 0;
  1311. }
  1312.  
  1313. /* Send raw packet on pi card */
  1314. int
  1315. pi_raw(iface,bp)
  1316. struct iface *iface;
  1317. struct mbuf *bp;
  1318. {
  1319.     char i_state;
  1320.     char kickflag;
  1321.     struct pichan *hp;
  1322.  
  1323.     dump(iface,IF_TRACE_OUT,CL_AX25,bp);
  1324.     iface->rawsndcnt++;
  1325.     iface->lastsent = secclock();
  1326.  
  1327.     hp = &Pichan[iface->dev];
  1328.     kickflag = (hp->sndq == NULLBUF) & (hp->sndbuf == NULLBUF);
  1329.     enqueue(&hp->sndq,bp);
  1330.     hp->enqueued++;
  1331.     if(kickflag){
  1332.         /* simulate interrupt to xmit */
  1333.         switch(hp->base & 2){
  1334.         case 2:
  1335.             a_txint(hp);        /* process interrupt */
  1336.             break;
  1337.         case 0:
  1338.             i_state = dirps();
  1339.             if(hp->tstate == IDLE)
  1340.                 b_txint(hp);
  1341.             restore(i_state);
  1342.             break;
  1343.         }
  1344.     }
  1345.     return 0;
  1346. }
  1347.  
  1348. /* display PI Channel stats */
  1349. int
  1350. dopistat()
  1351. {
  1352.     struct pichan *hp;
  1353.     int i;
  1354.  
  1355.     tprintf("PI Board Statistics:\n\n");
  1356.     tprintf("Base Addr  Rxints  Txints  Exints  TxFrms  RxFrms  Crcerr  RxOvrs  TxUndr \n");
  1357.     tprintf("---------  ------  ------  ------  ------  ------  ------  ------  ------ \n");
  1358.     for(i=0; i<pinbr*2; i++){
  1359.         hp = &Pichan[i];
  1360.  
  1361.         tprintf("0x%03x    % 8lu% 8lu% 8lu% 8u% 8u% 8u% 8u% 8u\nRcv State=%s ",
  1362.          hp->base, hp->rxints, hp->txints, hp->exints, hp->enqueued,
  1363.          hp->rxframes, hp->crcerr, hp->rovers, hp->tunders,
  1364.          hp->rstate==0 ?
  1365.           "IDLE" : hp->rstate==1 ?
  1366.            "ACTIVE" : hp->rstate==2 ?
  1367.             "RXERROR" : hp->rstate==3 ?
  1368.              "RXABORT":"TOOBIG"
  1369.         );
  1370.  
  1371.         tprintf("Tstate = %s\n",
  1372.          hp->tstate == 0 ?
  1373.           "IDLE" : hp->tstate == 1 ?
  1374.            "ACTIVE" : hp->tstate == 2 ?
  1375.             "UNDERRUN" : hp->tstate == 3 ?
  1376.              "FLAGOUT" : hp->tstate == 4 ?
  1377.               "DEFER" : hp->tstate == 5 ?
  1378.                "TXDELAY" : "CRCOUT"
  1379.         );
  1380.     }
  1381.     return 0;
  1382. }
  1383.  
  1384. /* Subroutine to set kiss params in channel tables */
  1385. int32
  1386. pi_ctl(iface,cmd,set,val)
  1387. struct iface *iface;
  1388. int cmd;
  1389. int set;
  1390. int32 val;
  1391. {
  1392.     struct pichan *hp;
  1393.     int32 t,ca;
  1394.  
  1395.     hp = &Pichan[iface->dev]; /* point to channel table */
  1396.     switch(cmd){
  1397.     case PARAM_TXDELAY:
  1398.         if(set)
  1399.             hp->txdelay = val;
  1400.         return hp->txdelay;
  1401.     case PARAM_PERSIST:
  1402.         if(set)
  1403.             hp->persist = val;
  1404.         return uchar(hp->persist);
  1405.     case PARAM_SLOTTIME:
  1406.         if(set)
  1407.             hp->slotime = val;
  1408.         return hp->slotime;
  1409.     case PARAM_TXTAIL:
  1410.         if(set)
  1411.             hp->squeldelay = val;
  1412.         return hp->squeldelay;
  1413.     }
  1414.     return -1;
  1415. }
  1416.